#ifndef __PARSER_H_
#define __PARSER_H_

#include <iostream>
#include <string>
#include <pcap.h>
#include <linux/udp.h>
#include <linux/ip.h>
#include <linux/if_ether.h>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>

// #include <boost/filesystem.hpp>
// #include <iomanip>

#include <ros/ros.h>
#include <sensor_msgs/PointCloud2.h>
#include <pcl_conversions/pcl_conversions.h>

#include <opencv2/opencv.hpp>

#include <unordered_map>
#include <vector>
#include <cmath>

using namespace std;
#define IP_HL(ip)               (((ip)->ip_vhl) & 0x0f)
#define IP_V(ip)                (((ip)->ip_vhl) >> 4)
#define SNAP_LEN 1518       // 以太网帧最大长度
#define SIZE_ETHERNET 14   // 以太网包头长度，其中MAC地址为 6*2, type占 2字节，共14字节
#define ETHER_ADDR_LEN  6  // mac地址长度
#define SIZE_UDP 8          // UDP头部长度
#define SIZE_PCAP   16      // PCAP头部长度

#define PCD_DURATION 0.1        // 每个pcd包含的扫描时间


#define SCANS 32             // 雷达扫描线数
#define FIRING_CYCLE 2.304      // 相邻两束雷达发射的时间间隔，单位是微秒 us
#define RECHARGEING_TIME 18.432     // 发射完16束激光后，需要重新充能，这是充能的时间，单位是微秒
#define SEQUENCE_TIME (FIRING_CYCLE * SCANS + RECHARGEING_TIME)     // 两列扫描之间的间隔
#define HORIZON_SPEED 3600          // 雷达一秒内旋转的角度
#define D2R (M_PI / 180.0)

class Parser
{
    
    private:
        /* IP header */
        struct packet_ip {
            u_char  ip_vhl;                 /* version << 4 | header length >> 2 */
            u_char  ip_tos;                 /* type of service */
            u_short ip_len;                 /* total length */
            u_short ip_id;                  /* identification */
            u_short ip_off;                 /* fragment offset field */
            #define IP_RF 0x8000            /* reserved fragment flag */
            #define IP_DF 0x4000            /* dont fragment flag */
            #define IP_MF 0x2000            /* more fragments flag */
            #define IP_OFFMASK 0x1fff       /* mask for fragmenting bits */
            u_char  ip_ttl;                 /* time to live */
            u_char  ip_p;                   /* protocol */
            u_short ip_sum;                 /* checksum */
            struct  in_addr ip_src,ip_dst;  /* source and dest address */
        };

        const float vertical_angle[SCANS] =      // 雷达扫描的垂直角度，以度为单位。这里的顺序是发射的顺序。         
        {-30.67 * D2R, -9.33 * D2R, -29.33 * D2R, -8 * D2R, -28 * D2R, -6.66 * D2R, -26.66 * D2R, -5.33 * D2R,
        -25.33 * D2R, -4.0 *D2R, -24.0 * D2R, -2.67 * D2R, -22.67 * D2R, -1.33 * D2R, -21.33 * D2R, 0 * D2R,
        -20 * D2R, 1.33 * D2R, -18.67 * D2R, 2.67 * D2R, -17.33 * D2R, 4 * D2R, -16 * D2R, 5.33 * D2R,
        -14.67 * D2R, 6.67 *D2R, -13.33 * D2R, 8.0 * D2R, -12 * D2R, 9.33 * D2R, -10.67 * D2R, 10.67 * D2R
        };

        const float vertical_correction[SCANS] =      // 雷达每根线垂直方向上的矫正，以毫米为单位。不太明白是干什么的。    
                {0};

        // 不同型号雷达的product id
        enum PRODUCT_ID
        {
            HDL_32E = 0x21,
            VLP_16 = 0x22,
            PUCK_LITE = 0x22,
            PUCK_HI_RES = 0x24,
            VLP_32C = 0x28,
            VELARRAY = 0x31,
            VLS_128 = 0x63
        };

        enum RETURN_MODE
        {
            STRONGUST = 0x37,
            LAST_RETURN = 0x38,
            DUAL_RETURN = 0x39
        };

        pcap_t *p;
        
        ros::Publisher point_pub;
        static std::ofstream f_out;

        static void read_callback(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
        void udpframe_decode(const std::string &header_packet, int &point_count, const int64_t &last_timestamp,pcl::PointCloud<pcl::PointXYZI> &cloud);
        void one_points_frame(std::vector<std::string> udp_frames, const int64_t &last_timestamp);

    public:
        Parser(const char* filepath);
        ~Parser();

        static std::unordered_map<int64_t, std::vector<std::string>> undecoder_points_sequence;

        void init();
        void decoder_points();
        pcl::PointCloud<pcl::PointXYZI> get_point_frame(const int64_t &timestamp);
};

#endif